package com.adcc.ags.gms.mq.service;

import com.adcc.ags.gms.core.entity.GWLogLevel;
import com.adcc.ags.gms.core.util.Constant;
import com.adcc.ags.gms.core.util.LogFactory;
import com.adcc.ags.gms.core.util.MQFactory;
import com.adcc.ags.gms.gw.service.SysConfigurationService;
import com.adcc.ags.gms.mq.entity.Queue;
import com.adcc.ags.gms.mq.mapper.QueueMapper;
import com.adcc.ags.gms.mq.vo.QueueVO;
import com.adcc.utility.mq.entity.ibm.IBMQueue;
import com.adcc.utility.mq.entity.ibm.LocalQueue;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.google.common.base.Optional;
import com.google.common.base.Strings;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.ibm.mq.MQException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Map;

/**
 * 队列服务层
 */
@Transactional
@Service("QueueService")
public class QueueServiceImpl implements QueueService {

    /**
     * 常量
     */
    // 系统队列名称
    private final static String SYS_QUEUE_NAME = "Q.S*";

    // 用户队列名称
    private final static String USR_QUEUE_NAME = "Q.U*";

    @Autowired
    private QueueMapper queueMapper;

    @Autowired
    private MQFactory mqFactory;

    @Autowired
    private SysConfigurationService configurationService;

    @Autowired
    private LogFactory log;

    /**
     * 查找所有用户队列
     * @return
     */
    private Optional<List<QueueVO>> findAllUserQueue() {
        try {
            List<QueueVO> result = Lists.newArrayListWithExpectedSize(1000);
            List<Queue> list = queueMapper.findAll();
            if (list != null && list.size() > 0) {
                for (Queue queue : list) {
                    QueueVO vo = new QueueVO(queue);
                    result.add(vo);
                }
            }
            return Optional.of(result);
        } catch (Exception ex) {
            log.error(QueueServiceImpl.class, "findAllUserQueue() error", ex);
            return Optional.absent();
        }
    }

    /**
     * 查找源用户队列
     * @param name
     * @return
     * @throws Exception
     */
    private LocalQueue findSourceUserQueue(String name) throws Exception {
        try {
            List<LocalQueue> list = mqFactory.getSourceMQM().findQueue(name);
            if (list != null && list.size() > 0) {
                for (LocalQueue queue : list) {
                    if (queue.getName().equals(name)) {
                        return queue;
                    }
                }
            }
            return null;
        } catch (Exception ex) {
            if (ex instanceof MQException) {
                if (((MQException) ex).getReason() == 2085) {
                    return null;
                } else {
                    throw ex;
                }
            } else {
                throw ex;
            }
        }
    }

    @Override
    public Optional<List<QueueVO>> findAllSysQueue() {
        try {
            List<QueueVO> result = Lists.newArrayListWithExpectedSize(1000);
            List<IBMQueue> list = mqFactory.getSourceMQM().findQueue(SYS_QUEUE_NAME);
            if (list != null && list.size() > 0) {
                long lDepth = Long.valueOf(configurationService.getValue(Constant.MQ_QUEUE_DEPTH));
                for (IBMQueue ibmq : list) {
                    QueueVO vo = new QueueVO(ibmq);
                    if(vo.getDepth() > lDepth){
                        log.warn(QueueService.class,"MQ","系统队列:" + vo.getName() + "当前深度超过告警阀值");
                        vo.setBlocked(true);
                    }
                    result.add(vo);
                }
            }
            return Optional.of(result);
        } catch (Exception ex) {
            log.error(QueueService.class,"MQ",GWLogLevel.SERIOUS_ALARM, "获取系统队列信息异常", ex);
            return Optional.absent();
        }
    }

    @Override
    public Optional<List<QueueVO>> findAllSourceUserQueue() {
        List<QueueVO> result = Lists.newArrayListWithExpectedSize(1000);
        try {
            List<IBMQueue> list = mqFactory.getSourceMQM().findQueue(USR_QUEUE_NAME);
            if (list != null && list.size() > 0) {
                long lDepth = Long.valueOf(configurationService.getValue(Constant.MQ_QUEUE_DEPTH));
                for (IBMQueue queue : list) {
                    QueueVO vo = new QueueVO(queue);
                    if(vo.getDepth() > lDepth){
                        vo.setBlocked(true);
                    }
                    result.add(vo);
                }
            }
            return Optional.of(result);
        } catch (Exception ex) {
            log.error(QueueService.class, "findAllSourceUserQueue() error", ex);
            return Optional.absent();
        }
    }

    @Override
    public Optional<List<QueueVO>> findAllTargetUserQueue() {
        List<QueueVO> result = Lists.newArrayListWithExpectedSize(1000);
        try {
            List<IBMQueue> list = mqFactory.getTargetMQM().findQueue(USR_QUEUE_NAME);
            if (list != null && list.size() > 0) {
                for (IBMQueue queue : list) {
                    QueueVO vo = new QueueVO(queue);
                    result.add(vo);
                }
            }
            return Optional.of(result);
        } catch (Exception ex) {
            log.error(QueueService.class, "findAllTargetUserQueue() error", ex);
            return Optional.absent();
        }
    }

    @Override
    public Queue findQueueById(Long id) {
        Queue queue = null;
        try {
            queue = queueMapper.findById(id);
        } catch (Exception ex) {
            log.error(QueueService.class, "findQueueById() error", ex);
        }
        return queue;
    }

    @Override
    public Optional<PageInfo<Queue>> findUserQueueByName(String name, int curPage, int pageSize) {
        try {
            PageHelper.startPage(curPage, pageSize);
            List<Queue> list = queueMapper.findByCondition(name);
            PageInfo<Queue> pageInfo = new PageInfo<>(list);
            return Optional.of(pageInfo);
        } catch (Exception ex) {
            log.error(QueueService.class,"MQ",GWLogLevel.ALARM,"查询用户队列失败", ex);
            return Optional.absent();
        }
    }

    @Override
    public Optional<List<QueueVO>> findUserQueueByEffect(boolean effect) {
        try {
            String strEnable = effect ? "T" : "F";
            List<QueueVO> result = Lists.newArrayListWithExpectedSize(1000);
            List<Queue> list = queueMapper.findByEnable(strEnable);
            if(list != null && list.size() > 0){
                for(Queue queue : list){
                    QueueVO vo = new QueueVO(queue);
                    result.add(vo);
                }
            }
            return Optional.of(result);
        } catch (Exception ex) {
            log.error(QueueService.class, "findUserQueueByEffect() error", ex);
            return Optional.absent();
        }
    }

    @Override
    public Optional<Boolean> isExistQueueName(String name) {
        try {
            int intCount = queueMapper.isExistQueueName(name);
            if (intCount > 0) {
                return Optional.of(true);
            } else {
                return Optional.of(false);
            }
        } catch (Exception ex) {
            log.error(QueueService.class,"MQ",GWLogLevel.ALARM,"校验用户队列:" + name + "失败", ex);
            return Optional.absent();
        }
    }

    @Override
    public Optional<Boolean> createQueue(QueueVO vo) {
        try {
            Queue queue = vo.toEntity();
            queueMapper.createQueue(queue);
            log.info(QueueService.class,"MQ", "新增用户队列:" + vo.getName());
            return Optional.of(true);
        } catch (Exception ex) {
            log.error(QueueService.class, "MQ", GWLogLevel.ALARM, "创建用户队列:" + vo.getName() + "失败", ex);
            return Optional.absent();
        }
    }

    @Override
    public Optional<Boolean> updateQueue(QueueVO vo) {
        try {
            Queue queue = vo.toEntity();
            queueMapper.updateQueueById(queue);
            log.info(QueueService.class,"MQ", "更新用户队列:" + vo.getName());
            return Optional.of(true);
        } catch (Exception ex) {
            log.error(QueueService.class,"MQ", GWLogLevel.ALARM, "更新用户队列:" + vo.getName() + "失败", ex);
            return Optional.absent();
        }
    }

    @Override
    public Optional<Boolean> deleteQueue(long id) {
        Queue queue = new Queue();
        try {
            queue = queueMapper.findById(id);
            if ("F".equals(queue.getEnable())) {
                queueMapper.deleteQueue(id);
                log.info(QueueService.class, "MQ", "删除用户队列：" + queue.getName());
                return Optional.of(true);
            } else {
                return Optional.of(false);
            }
        } catch (Exception ex) {
            log.error(QueueService.class, "MQ", GWLogLevel.ALARM, "删除用户队列:" + queue.getName() + "失败", ex);
            return Optional.absent();
        }
    }

    @Override
    public Optional<Boolean> onEnable(long id) {
        Queue queue = new Queue();
        try {
            queue = queueMapper.findById(id);
            if (queue == null) {
                return Optional.of(false);
            } else {
                LocalQueue lq = findSourceUserQueue(queue.getName());
                if (lq != null) {
                    mqFactory.getSourceMQM().removeQueue(lq);
                }
                LocalQueue localQueue = new LocalQueue();
                localQueue.setName(queue.getName());
                localQueue.setType(queue.getType());
                localQueue.setPriority(queue.getPriority());
                if (queue.getPersistent() == 0) {
                    localQueue.setPersistent(false);
                } else {
                    localQueue.setPersistent(true);
                }
                localQueue.setMaxDepth(queue.getMaxDepth());
                localQueue.setMaxMsgLength(queue.getMaxMsgLength());
                localQueue.setRetainInterval(queue.getRetainInterval());
                mqFactory.getSourceMQM().createQueue(localQueue);
                queue.setEnable("T");
                queueMapper.updateQueueById(queue);
                log.info(QueueService.class, "MQ", "用户队列:" + queue.getName() + "生效");
                return Optional.of(true);
            }
        } catch (Exception ex) {
            log.error(QueueService.class,"MQ", GWLogLevel.ALARM, "生效用户队列:" + queue.getName() + "失败", ex);
            return Optional.absent();
        }
    }

    @Override
    public Optional<Boolean> onDisable(Long id) {
        Queue queue = new Queue();
        try {
            queue = queueMapper.findById(id);
            if (queue == null) {
                return Optional.of(false);
            } else {
                LocalQueue lq = findSourceUserQueue(queue.getName());
                if (lq != null) {
                    mqFactory.getSourceMQM().removeQueue(lq);
                }
                queue.setEnable("F");
                queueMapper.updateQueueById(queue);
                log.info(QueueService.class,"MQ", "失效用户队列:" + queue.getName() + "");
                return Optional.of(true);
            }
        } catch (Exception ex) {
            log.error(QueueService.class,"MQ", GWLogLevel.ALARM, "失效用户队列:" + queue.getName() + "失败", ex);
            return Optional.absent();
        }
    }

    @Override
    public Optional<Map<String, List<QueueVO>>> analyzeSyncQueue() {
        try {

            // 目标队列与当前队列差异列表
            Map<String, List<QueueVO>> map = Maps.newHashMapWithExpectedSize(1000);

            // 取得目标用户队列
            Optional<List<QueueVO>> optlTarget = findAllTargetUserQueue();
            if (!optlTarget.isPresent()) {
                return Optional.absent();
            }

            // 取得当前用户队列
            Optional<List<QueueVO>> optlSource = findAllUserQueue();
            if (!optlSource.isPresent()) {
                return Optional.absent();
            }

            // 取得目标队列有当前队列没有的队列
            List<QueueVO> listNewQueue = Lists.newArrayListWithExpectedSize(1000);
            List<QueueVO> listDiffQueue = Lists.newArrayListWithExpectedSize(1000);
            for (QueueVO target : optlTarget.get()) {
                if (optlSource.get() != null && optlSource.get().size() > 0) {
                    boolean flag = false;
                    for (QueueVO source : optlSource.get()) {
                        if (source.getName().equals(target.getName())) {
                            flag = true;
                            String strResult = target.compare(source);
                            if (!Strings.isNullOrEmpty(strResult)) {
                                target.setCompareResult(strResult);
                                listDiffQueue.add(target);
                            }
                            break;
                        }
                    }
                    if (!flag) {
                        listNewQueue.add(target);
                    }
                } else {
                    listNewQueue.add(target);
                }
            }
            map.put("newQueue", listNewQueue);
            map.put("diffQueue", listDiffQueue);
            return Optional.of(map);
        } catch (Exception ex) {
            log.error(QueueService.class, "MQ", GWLogLevel.ALARM, "比较同步队列失败", ex);
            return Optional.absent();
        }
    }

    @Override
    public Optional<Boolean> syncQueue(List<QueueVO> newList, List<QueueVO> diffList) {
        try {

            // 同步新增队列
            if (newList.size() > 0) {
                for (QueueVO vo : newList) {
                    try {
                        LocalQueue lq = new LocalQueue();
                        lq.setName(vo.getName());
                        lq.setPriority(vo.getPriority());
                        lq.setPersistent(vo.getPersistent());
                        lq.setMaxDepth(vo.getMaxDepth());
                        lq.setMaxMsgLength(vo.getMaxMsgLength());
                        lq.setRetainInterval(vo.getRetainInterval());
                        mqFactory.getSourceMQM().createQueue(lq);
                        Queue queue = vo.toEntity();
                        queueMapper.createQueue(queue);
                    } catch (Exception ex) {
                        log.error(QueueService.class, "sync queue:" + vo.getName() + " failed", ex);
                    }
                }
            }

            // 队列属性有差异
            for (QueueVO vo : diffList) {
                try {
                    LocalQueue lq = new LocalQueue();
                    lq.setName(vo.getName());
                    lq.setPriority(vo.getPriority());
                    lq.setPersistent(vo.getPersistent());
                    lq.setMaxDepth(vo.getMaxDepth());
                    lq.setMaxMsgLength(vo.getMaxMsgLength());
                    lq.setRetainInterval(vo.getRetainInterval());
                    mqFactory.getSourceMQM().updateQueue(lq);
                    Queue queue = vo.toEntity();
                    queueMapper.updateQueueByName(queue);
                } catch (Exception ex) {
                    log.error(QueueService.class, "sync queue:" + vo.getName() + " failed", ex);
                }
            }
            log.info(QueueService.class, "MQ", "同步用户队列");
            return Optional.of(true);
        } catch (Exception ex) {
            log.error(QueueService.class, "MQ", GWLogLevel.ALARM, "同步用户队列失败", ex);
            return Optional.absent();
        }
    }

    @Override
    public Optional<Boolean> clearQueue(String name) {
        try{
            mqFactory.getSourceMQM().clearQueue(name);
            return Optional.of(true);
        }catch (Exception ex){
            log.error(QueueService.class,"clearQueue() error",ex);
            return Optional.absent();
        }
    }

    @Override
    public long queueCurrentDepth(long id) {
        Queue queue = new Queue();
        long depth = 0;
        try {
            queue = queueMapper.findById(id);
            List<LocalQueue> list = mqFactory.getSourceMQM().findQueue(queue.getName());
            if (list != null && list.size() > 0) {
                for (IBMQueue ibmQueue : list) {
                    depth = ibmQueue.getDepth();
                }
            }
        } catch (Exception ex) {
            log.error(QueueService.class, "queueCurrentDepth() error", ex);
        }
        return depth;
    }
}
